// console.log(foo);

// function foo(){
//     console.log("foo");
// }

// var foo = 1;
// ------
// var dad = {};
// var son = {};
// function show(){
//   return this;
// }
// var newShow = show.bind(dad);//dad
// var newShow1 = newShow.bind(son);//son
// console.log(newShow() == dad);//true
// console.log(newShow1() == son);//true
// ------
// this.a = 1;
// var module = {
//     a : 2,
//     getA: function() {
//     return this.a;
//     }
// };
// module.getA();//
// var getA1 = module.getA;
// // getA在外部调用，此时的this指向了全局对象
// getA1();//
// // 再把getA1方法绑定到module环境上
// var getA2 = getA1.bind(module);
// getA2();
// ----
// call 和 apply  作用：改变this指向。 区别：传参列表不同。
// call(this, 参数1, 参数2..) | apply(this, [参数1, 参数2..])
//   call需要把实参按照形参的个数传进去， apply 需要传一个arguments（数组）
// function test(){};
// test() --> test.call(); test()函数执行就是test.call()
// fun.call(指定的this, val1, val2, val3...);  利用别人的方法，实现自己的功能

// var name = 'www';
// var age = 17;
// var obj = {
//   name: 'zzz',
//   age: 18
// }
// function fun(){
//   console.log(this.name, this.age);
// }
// // fun();//www 17
// fun.call(obj);//zzz 18

// 借用构造函数继承
/*
function Person(name, age, sex){
  this.name = name;
  this.age = age;
  this.sex = sex;
}
function Student(name, age, sex, tel, grade){
  // var this = {name: '', age: '', sex: ''}
  Person.call(this, name, age, sex);//相当于把Person里面的代码复制在这里
  // 相当于
  // this.name = name;
  // this.age = age;
  // this.sex = sex;
  this.tel = tel;
  this.grade = grade;
}
var student = new Student('sunny', 18, 'male', 139, 2017);
console.log(student);
*/

// 函数中 参数按值传递
// 原始类型传递副本 引用类型传递对象的引用
// 按值传递很好理解，把函数外部的值复制给函数内部的参数，就和把值从一个变量复制到另一个变量一样。

// var value = 1;
// function f(v){
//   v= 2;
//   console.log(v);//2
// }
// f(value);
// console.log(value);//1

// 引用类型传递对象的引用

// var obj = {
//   value: 1
// }
// function f(o){
//   o.value= 2;
//   console.log(o.value);//2
// }
// f(obj);
// console.log(obj.value);//2

// 参数传递方式说的就是从实参给形参复制的过程
// 值传递就是把实参在内存栈中的数据传递给形参, 
// 然后你在方法内部就可以使用形参了, 而引用传递是把实参的内存栈的地址编号传递给形参.
// 按共享传递依然是按值传递，
// 我也是这样认为的呐，很多人还认为按引用传递也是按值传递，只是值是指针(地址)而已，这个说法也对

// call 和 apply 的模拟实现
// 一句话介绍call : call()方法在使用一个指定的this值和若干个指定过的参数值的前提下调用某个函数或方法
// 模拟实现一个call
// var foo = {
//   value: 1
// }
// var value = 2;
// function bar(){
//   console.log(this.value);
// }
// bar();//2
// bar.call(foo);//1

/*
当使用bar.call(foo)时，this指向了foo这个对象,我们可以这样写
foo= {
  value: 1,
  fn: function(){ console.log(this.value) }
}
这样的话this就指向了foo对象
所以当call()时，我们可以把bar方法放在foo对象当中，执行后在删除这个属性，
所以模拟一个call方法步骤是：
1，把函数设为这个对象的属性
2，执行这个函数
3，删除这个函数
*/ 
// Object.prototype.call2 = function(obj){
//     obj.fn = this;
//     obj.fn();
//     delete obj.fn;
// }
// var foo = {
//   value: 1
// }
// function bar(){
//   console.log(this.value);
// }
// bar.call2(foo);

// ----
// bind

// 根据Object.prototype.toString.call(value) 判断值的类型
/*
function myTypeOf(value){
    var res = Object.prototype.toString.call(value);
    console.log(res.match(/\[object (.*?)\]/)[1].toLowerCase())
}
myTypeOf({});
 */

//  继承 圣杯模式
/*
function inherit(Target, Origin){
  function F(){};
  F.prototype = Origin.prototype;
  Target.prototype = new F();
  Target.prototype.consturctor = Target;//设置construct
  Target.prototype.uber = Origin.prototype;//设置他继承自谁
}
Farther.prototype.lastName = 'Deng';
function Farther(){};
function Son(){};
inherit(Son, Farther);
var son = new Son();
var farther = new Farther();
*/
/*
// 雅虎的js封装方法
var inherit = (function (){
    var F = function(){};
    return function (Target, Origin){
      F.prototype = Origin.prototype;
      Target.prototype = new F();
      Target.prototype.consturctor = Target;//设置construct
      Target.prototype.uber = Origin.prototype;//设置他继承自谁`
  }
})
*/ 

// 使用闭包私有化变量
/*
function Deng(name, wife){
    var prepareWife = 'xiaozhang';
    this.name = name;
    this.wife = wife;
    this.divorce = function(){
      this.wife = prepareWife;
    }
    this.changePrepareWife = function(Target){
      prepareWife = target;
    }
    this.sayPraprewife = function(){
      console.log(this.prepareWife);
    }
}
var deng = new Deng('dneg', 'xiaowang');
*/
// 命名空间
// 使用对象分层来做命名区分、

//使用闭包 实现命名空间
var name = 'b'
var init= (function (){
  var name = 'www';
  function callName(){
    console.log(name);
  }
  return function(){
    callName();
  }
}())
init();//'www'

// 模块化开发使用闭包，防止命名污染 ，尤其是开发插件时


// 对象枚举 仿jQeury 连续调用
var deng = {
  smoke : function(){
    console.log('smoke.....');
    return this;
    //返回的是deng 然后就可以实现
    // 连续调用 deng.smoke().drink();
  },  
  drink : function(){
    console.log('drink.....');
    return this;
  }
}
deng.smoke().drink();

// 对象[] 的应用
var deng = {
  wife1 : {name: 'xiaozhang'},
  wife2 : {name: 'xiaowan'},
  wife3 : {name: 'xiaoliu'},
  sayWife: function(num){
    return this['wife' + num].name;
  }
}
deng.sayWife(2)

// 对象遍历

var o = {
  name: 'zzz',
  age: 13,
  sex: 'man'
}
o.__proto__.sbu='123';
for(var v in o){//必须写  对象[属性名 ]  只能遍历出自己写的原型的属性
  //console.log(o.v);//---> o['v'] -> 5* undefined
  if(o.hasOwnProperty(prop)){ //判断是不是自己的属性 返回true false
    console.log(o[v]);//遍历属性的值 
  }
  console.log(v);//遍历属性
}
//会遍历自己原型上的属性;
//in 本身也是一个操作符 判断对象中是否有此属性 可以判断原型

Object.keys(o);//不会遍历原型上的属性

// hasOwnProperty(属性名字符串形式)  判断是不是自己的属性 true false


// in
// name in obj -> 属性一定是字符串 ‘’ --> 'name' in obj 
//不加字符串的都是变量
//原型上和自己的都会检测

// instanceOf 
//-- > A instanceOf B 
//               A对象 是不是 B构造函数构造出来的   
// 总结一句话   看 A 对象原型链上有没有 B 的原型 

// 区别 一个变量是数组还是对象
function typeOf2(value){
  return Object.prototype.toString.call(value).slice(8, -1);
}

// 克隆 浅克隆 深克隆

// 下边的代码x y z 的结果
var x= 1; y= z= 0;
function add(n){
    return n= n+1;
}
y = add(x);
function add(n){
  return n = n+ 3;
}
z = add(x);
//x = 4; y = 4; z= 7;
//1

function foo(x){
  console.log(arguments);//[1,2,3,4,5]
  return x;
}
foo(1,2,3,4,5)
// 2
function foo(){
  bar.apply(null, arguments);
  //--> bar(arguments)
}
function bar(){
  console.log(arguments);
}
foo(1,2,3,4,5);

// 3 水平垂直居中
// line-height = height;
// text-align:cneter;

// 结果
parseInt(3, 8);
parseInt(3, 2);
parseInt(3, 0);

// 3 NaN 3/NaN

// 进制
// 满足一个数 从个位进十 满几进十
// 十进制
// 1 = 1
// 10 = 10
// 100 = 10^2
// 1000 = 10^3
// 10000 = 10^4
// 二进制
// 1 = 1
// 10 = 2
// 100 =2^2
// 1000 = 2^3
// 10000 = 2^4

// typeOf 返回的结果 
//Number String Boolean undefined Function Object
// 五大基础类型 + 一个引用类型 = 6
// 五大基础类型返回了四种, null归到了object中, 在加一个 Function

// call和apply 干什么的 有什么区别
// 改变this指向 ，传参列表不同 ，call传值，apply 传数组


function b(x, y, a){
  arguments[2] = 10;
  console.log(a);
  // a = 10;
  // console.log(arguments[2]);
}
b(1, 2, 3);
// 形参和arguments是映射关系 但不是一个人 要变都变


// 逗号操作符
// var a= (1,2);
// 那就是：var a = 2;